package com.yanh.gateway.filter;

import com.alibaba.fastjson.JSON;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;


import com.yanh.common.config.JwtConfig;
import com.yanh.common.enums.ResultCode;
import com.yanh.common.domain.Result;
import com.yanh.common.security.TokenConstant;
import com.yanh.common.security.TokenUtil;
import com.yanh.common.utils.HttpUtil;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Configuration
@RequiredArgsConstructor
public class TokenValidationGlobalFilter {

    /**
     * 白名单
     */
    private List<String> wihtelsit= new ArrayList<>();

    /**
     * 放行链接
     */
    private List<String> resourceWihtelsit= Arrays.asList(
            "/webjars/**",
            "/doc.html",
            "/swagger-resources/**",
            "/v3/api-docs/**",
            "/swagger-ui/**"
    );

    private final JwtConfig jwtConfig;

    private final TokenUtil tokenUtil;
    private final AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Bean
    @Order(-101)
    public GlobalFilter jwtAuthGlobalFilter() {
        return (exchange, chain) -> {

            ServerHttpRequest serverHttpRequest = exchange.getRequest();
            ServerHttpResponse serverHttpResponse = exchange.getResponse();
            ServerHttpRequest.Builder mutate = serverHttpRequest.mutate();

            //1.获取AUTHORIZATION请求头,没有请求头或value不是以Bearer开头放行请求,SecurityFilterChain判断是否可以请求(security)
//            String authorization = serverHttpRequest.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
//            if (StrUtil.isBlank(authorization) || !StrUtil.startWithIgnoreCase(authorization, TokenConstant.PREFIX)) {
//                return chain.filter(exchange);
//            }

            //1.判断是否不需要拦截
            if(isExcludePathPatterns(serverHttpRequest.getPath().toString())){
                // 放行
                return chain.filter(exchange);
            }

            //2.从 HTTP 请求头中获取token
            String token = HttpUtil.getTokenFromHttpRequest(serverHttpRequest);
            //结合redis 来校验token-todo

            //3.对Token解签名，并验证Token是否过期
            boolean isJwtNotValid = tokenUtil.isTokenExpired(token);
            if(isJwtNotValid){
                return unauthorizedResponse(exchange, serverHttpResponse, ResultCode.TOKEN_INVALID);
            }

            //4.验证 token 里面的 userId 是否为空
            String userId = tokenUtil.getUserIdFromToken(token);
            String username = tokenUtil.getUserNameFromToken(token);
            if (StringUtils.isEmpty(userId)) {
                return unauthorizedResponse(exchange, serverHttpResponse, ResultCode.TOKEN_CHECK_INFO_FAILED);
            }

            //5.设置用户信息到请求
            HttpUtil.addHeader(mutate, TokenConstant.USER_ID, userId);
            HttpUtil.addHeader(mutate, TokenConstant.USER_NAME, username);
            HttpUtil.removeHeader(mutate, TokenConstant.FROM_SOURCE);// 内部请求来源参数清除
            return chain.filter(exchange.mutate().request(mutate.build()).build());
        };
    }
    /**
     * 路径匹配
     */
    private boolean isExcludePathPatterns(String antPath) {
        wihtelsit.addAll(jwtConfig.getWhiteList());
        wihtelsit.addAll(resourceWihtelsit);
        for (String pathPattern : wihtelsit) {
            if(antPathMatcher.match(pathPattern, antPath)){
                return true;
            }
        }
        return false;
    }

    /**
     * 将 JWT 鉴权失败的消息响应给客户端
     */
    private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, ServerHttpResponse serverHttpResponse, ResultCode responseCodeEnum) {
        serverHttpResponse.setStatusCode(HttpStatus.UNAUTHORIZED);
        serverHttpResponse.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        Result responseResult = Result.error(responseCodeEnum.getCode(), responseCodeEnum.getMessage());
        DataBuffer dataBuffer = serverHttpResponse.bufferFactory()
                .wrap(JSON.toJSONStringWithDateFormat(responseResult, JSON.DEFFAULT_DATE_FORMAT)
                        .getBytes(StandardCharsets.UTF_8));
        return serverHttpResponse.writeWith(Flux.just(dataBuffer));
    }
}